package com.twq.collection.framework.seq

import scala.reflect.ClassTag

/**
 * Created by tangweiqun on 2017/12/10.
 */
object ArraysTest {
  def main(args: Array[String]): Unit = {
    //Array是一种特殊的集合。Scala中的数组和Java中的数组是一对一的，比如：
    //Array[Int]对应着java中int[]，Array[String]对应着java中的String[]等

    //但是scala中的Array比java中的数组功能更强大：

    //1、Scala中的Array是带有类型参数的，比如Array[T] ==> T[]

    //在构建泛型数组的时候需要让编译器将泛型类型告知运行时。因为：
    // (1)运行时需要根据类型来构建不同的jvm数组
    // (2)所有的泛型在运行的时候都是擦除的
    def evenElems[T: ClassTag](xs: Vector[T]): Array[T] = {
      val arr = new Array[T]((xs.length + 1) / 2)
      for (i <- 0 until xs.length by 2)
        arr(i / 2) = xs(i)
      arr
    }

    //2、Scala中的Array是兼容Seq的，比如：
    def test(seq: Seq[Int]) = seq.foreach(println)

    test(Array(1, 2, 3)) //可以将Array传给Seq

    val a1 = Array(1, 2, 3)
    val seq: Seq[Int] = a1

    //这个是因为在scala.LowPriorityImplicits中含有一个隐式转换，
    // 这个隐式转换将Array[T]转换成WrappedArray[T]类型，而WrappedArray[T]是Seq的子类

    //3、Scala中的Array支持Seq中的所有方法，比如：
    val a2 = a1 map (_ * 3)
    val a3 = a2 filter (_ % 2 != 0)
    a3.reverse

    //这个是因为在scala.PreDef中存在一个隐式转换，
    // 这个隐式转换是将Array[T]类型转换称ArrayOps[T]类型，ArrayOps并不是Seq的子类，但是包含了Seq中的所有方法

    //4、两个问题：
    //4.1、为什么会存在两个隐式转换呢？
    //第一个转成WrappedArray[T]是为了使得Array兼容Seq。如果你调用WrappedArray[T]中的方法，那么返回的就是WrappedArray[T]
    val seqTmp: Seq[Int] = a1
    seqTmp.reverse //res2: Seq[Int] = WrappedArray(3, 2, 1).... 这个并不是我们想要的

    val ops: collection.mutable.ArrayOps[Int] = a1
    ops.reverse // res3: Array[Int] = Array(3, 2, 1) 这个才是我们想要的

    scala.Predef

    //4.2、有两个隐式转换的话，那怎么能找对是哪个隐式转换呢？
    //两个隐式转换的查找是有优先级的:
    //scala.LowPriorityImplicits是scala.PreDef的父类，所以隐式查找的时候会去先查找scala.PreDef中的隐式转换
    //所以对于Array方法的调用，肯定会先找到scala.PreDef中的隐式转换
    //对于Array兼容Seq则会找到scala.LowPriorityImplicits中的隐式转换，因为ArrayOps并不是Seq的子类


  }
}
